#include "function_c.h"
#include <func.h>

int funcjudge(const char* buf)
{
    char buf1[1024]={0};
    char buf2[1024]={0};
    sscanf(buf,"%s %s",buf1,buf2);
    if(strcmp(buf1,"exit")==0||strcmp(buf1,"EXIT")==0) return CMD_TYPE_EXIT;
    if(strcmp(buf1,"cd")==0||strcmp(buf1,"CD")==0) return CMD_TYPE_CD;
    if(strcmp(buf1,"ls")==0||strcmp(buf1,"LS")==0) return CMD_TYPE_LS;
    if(strcmp(buf1,"ll")==0||strcmp(buf1,"LL")==0) return CMD_TYPE_LL;
    if(strcmp(buf1,"pwd")==0||strcmp(buf1,"PWD")==0) return CMD_TYPE_PWD;
    if(strcmp(buf1,"getsfile")==0||strcmp(buf1,"GETSFILE")==0) return CMD_TYPE_GETSFILE;
    if(strcmp(buf1,"putsfile")==0||strcmp(buf1,"PUTSFILE")==0) return CMD_TYPE_PUTSFILE;
    if(strcmp(buf1,"mv")==0||strcmp(buf1,"MV")==0) return CMD_TYPE_MV;
    if(strcmp(buf1,"cp")==0||strcmp(buf1,"CP")==0) return CMD_TYPE_CP;
    if(strcmp(buf1,"rm")==0||strcmp(buf1,"RM")==0) return CMD_TYPE_RM;
    if(strcmp(buf1,"rmdir")==0||strcmp(buf1,"RMDIR")==0) return CMD_TYPE_RMDIR;
    if(strcmp(buf1,"mkdir")==0||strcmp(buf1,"MKDIR")==0) return CMD_TYPE_MKDIR;
    else return -1;
}

void set_nonblock(int fd){
    int flag=fcntl(fd,F_GETFL,0);
    flag|=O_NONBLOCK;
    fcntl(fd,F_SETFL,flag);
}

int create_connect(int port,const char* ip){
    int clientfd=socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    addr.sin_family=AF_INET;
    addr.sin_port=htons(port);
    addr.sin_addr.s_addr=inet_addr(ip);
    connect(clientfd,(struct sockaddr*)&addr,sizeof(addr));
    return clientfd;
}

int create_epoll(int fd){
    int efd=epoll_create1(0);
    add_r_epoll(efd,fd);
    return efd;
}

void del_epoll(int efd,int fd){
    struct epoll_event listevent;
    listevent.data.fd=fd;
    epoll_ctl(efd,EPOLL_CTL_DEL,fd,&listevent);
}

void add_rw_epoll(int efd,int fd){
    struct epoll_event listevent;
    memset(&listevent,0,sizeof(listevent));
    listevent.data.fd=fd;
    listevent.events=EPOLLIN|EPOLLOUT;
    epoll_ctl(efd,EPOLL_CTL_ADD,fd,&listevent);
}

void add_r_epoll(int efd,int fd){
    struct epoll_event listevent;
    memset(&listevent,0,sizeof(listevent));
    listevent.data.fd=fd;
    listevent.events=EPOLLIN;
    epoll_ctl(efd,EPOLL_CTL_ADD,fd,&listevent);
}

int sendbigfile(int peerfd,const char* pthname1,const char* pthname2);

int dfs_puts(int peerfd,const char* pthname1,const char* pthname2,int deep);

int putsfile_c(int peerfd,char *dir)
{
    int ret;
    struct stat statbuf;
    ret=stat(dir,&statbuf);
    if(ret==-1) return ret;
    int j=0;
    for(int i=0;i<strlen(dir);i++){
        if(dir[i]=='/'){
            j=i;
        }
    }
    char* buff=&dir[j+1];
    if((statbuf.st_mode & S_IFMT)==S_IFDIR){
        ret=send(peerfd,"1",1,MSG_WAITALL);
        if(ret!=1) return ret;
        train_t train;
        memset(&train, 0, sizeof(train));
        train.length = strlen(buff);
        strcpy(train.buff, buff);
        ret = send(peerfd, &train, 4 + train.length, MSG_WAITALL);
        if(ret!=4 + train.length) return ret;
        ret=dfs_puts(peerfd,dir,buff,1);
        return ret;
    }
    else{
        ret=send(peerfd,"0",1,MSG_WAITALL);
        if(ret!=1) return ret;
        ret=sendbigfile(peerfd,dir,buff);
        if(ret<=0) return ret;
        ret=send(peerfd,"2",1,MSG_WAITALL);
        return ret;
    }
}

int dfs_puts(int peerfd,const char* pthname1,const char* pthname2,int deep)
{
    DIR* pdir=opendir(pthname1);
    if(pdir==NULL) return -1;
    struct dirent* pdirent;
    errno=0;
    int ret;
    while((pdirent=readdir(pdir))!=NULL){
        if(errno!=0) return -1;
        if(pdirent->d_name[0]=='.'){
            continue;
        }
        char filename1[1024]={0};
        char filename2[1024]={0};
        sprintf(filename1,"%s/%s",pthname1,pdirent->d_name);
        sprintf(filename2,"%s/%s",pthname2,pdirent->d_name);
        if(pdirent->d_type==DT_DIR){
            ret=send(peerfd,"1",1,MSG_WAITALL);
            if(ret!=1) return ret; 
            train_t train;
            memset(&train, 0, sizeof(train));
            train.length = strlen(filename2);
            strcpy(train.buff, filename2);
            ret = send(peerfd, &train, 4 + train.length, MSG_WAITALL);
            if(ret!=4 + train.length) return ret;
            dfs_puts(peerfd,filename1,filename2,deep+1);
            errno=0;
        }
        else {
            ret=send(peerfd,"0",1,MSG_WAITALL);
            if(ret!=1) return 1;
            if((ret=sendbigfile(peerfd,filename1,filename2))!=1) return ret;
            errno=0;
        }
    }
    if(deep==1){
        ret=send(peerfd,"2",1,MSG_WAITALL);
        return ret;
    }
}

int sendbigfile(int peerfd, const char* pthname1,const char* pthname2){
    printf("%s is uploading!\n",pthname2);
    int fds[2];
    pipe(fds);
    int fd=open(pthname1,O_RDWR);
    if(fd==-1) return -1;
    train_t train;
    memset(&train, 0, sizeof(train));
    train.length = strlen(pthname2);
    strcpy(train.buff, pthname2);
    int ret = send(peerfd, &train, 4 + train.length, MSG_WAITALL);
    if(ret!=4 + train.length) return ret;
    struct stat st;
    memset(&st,0,sizeof(st));
    fstat(fd, &st);
    ret=send(peerfd, &st.st_size, 8, MSG_WAITALL);
    printf("the length of uploadfile %s is %ld\n",pthname2,st.st_size);
    if(ret!=8) return ret;
    size_t sendSize = 0;
    size_t percentOne = st.st_size / 100;
    size_t lastSize = 0;
    size_t recvSize = 0;
    while(sendSize < st.st_size){
        int ret=splice(fd,NULL,fds[1],NULL,1024,SPLICE_F_MORE);
        ret=splice(fds[0],NULL,peerfd,NULL,ret,SPLICE_F_MORE);
        if(ret<=0) return ret;
        sendSize+=ret;
        if(recvSize - lastSize > percentOne) {
            printf("%s has upload %5.2f%%\r",pthname2, (double)recvSize / st.st_size * 100);
            fflush(stdout);
            lastSize = recvSize;
        }
    }
    printf("%s has complete 100.00%%\n",pthname2);
    return 1;
} 

int recvn(int fd,char* buff,int length)
{
    char* pbuf=buff;
    int left=length;
    int ret=0;
    while(left>0){
        ret=recv(fd,pbuf,left,0);
        if(ret<=0)  return ret;
        else{
            pbuf+=ret;
            left-=ret;
        }
    }
    return 1;
}

int getsfile_c(int peerfd)
{
    int fds[2];
    pipe(fds);
    while(1){
        char ch;
        int ret=recvn(peerfd,&ch,1);
        if(ret!=1) return ret;
        printf("ch=%c\n",ch);
        int length;
        ret = recv(peerfd, &length, 4,MSG_WAITALL);
        if(ret!=4 ) return ret;
        char pthname[1024]={0};
        ret=recvn(peerfd,pthname,length);
        printf("%s is downloading!\n",pthname);
        int fd;
        if(ch=='0'){
            fd = open(pthname, O_RDWR|O_CREAT|O_TRUNC, 0666); 
            if(fd==-1) return -1;
        }else if(ch=='1'){
            ret=mkdir(pthname,0777);
            if(ret==-1) return -1;
            continue;
        }else if(ch=='2') break;
        size_t filelength = 0;
        ret=recvn(peerfd,(char*)&filelength, 8);
        if(ret!=1) return ret;
        printf("%s need download length: %ld\n",pthname,filelength);
        size_t percentOne = filelength / 100;
        size_t lastSize = 0;
        size_t recvSize = 0;
        while(recvSize < filelength) {
            int lastonceSize = filelength - recvSize;
            if(filelength - recvSize < 1024) {
                ret=splice(peerfd,NULL,fds[1],NULL,lastonceSize,SPLICE_F_MORE);
                ret=splice(fds[0],NULL,fd,NULL,ret,SPLICE_F_MORE);
            }else {
                ret=splice(peerfd,NULL,fds[1],NULL,1024,SPLICE_F_MORE);
                ret=splice(fds[0],NULL,fd,NULL,ret,SPLICE_F_MORE);
            }
            if (ret<=0) return ret;
            recvSize += ret;
            if(recvSize - lastSize > percentOne) {
                printf("%s has download %5.2f%%\r",pthname, (double)recvSize / filelength * 100);
                fflush(stdout);
                lastSize = recvSize;
            }
        }
        printf("%s has complete 100.00%%\n",pthname);
    }
    return 1;
}

int getsfileplus_c(int peerfd,const char* pthname)
{
    int fds[2];
    pipe(fds);
    size_t hasrecv=0;
    size_t percentOne =0;
    size_t lastSize = 0;
    size_t recvSize = 0;
    size_t filelength = 0;
    int fd;
    struct stat statbuf;
    int ret=stat(pthname,&statbuf);
    if(ret==-1){
        ret=send(peerfd,&hasrecv,8,MSG_WAITALL);
        if(ret!=8) return ret;
        int length;
        ret = recv(peerfd, &length, 4,MSG_WAITALL);
        if(ret!=4 ) return ret;
        char pthname[1024]={0};
        ret=recvn(peerfd,pthname,length);
        printf("%s is downloading!\n",pthname);
        int fd = open(pthname, O_RDWR|O_CREAT|O_TRUNC, 0666); 
        if(fd==-1) return -1;
        ret=recvn(peerfd,(char*)&filelength, 8);
        if(ret!=1) return ret;
        printf("%s need download length: %ld\n",pthname,filelength);
    }else{
        hasrecv=statbuf.st_size;
        ret=send(peerfd,&hasrecv,8,MSG_WAITALL);
        if(ret!=8) return ret;
        int fd = open(pthname, O_WRONLY|O_APPEND, 0666); 
        if(fd==-1) return -1;
        ret=recvn(peerfd,(char*)&filelength, 8);
        if(ret!=1) return ret;
        printf("%s need download length: %ld\n",pthname,filelength);
    }
    percentOne = filelength / 100;
    while(recvSize < filelength) {
        int lastonceSize = filelength - recvSize;
        if(filelength - recvSize < 1024) {
            ret=splice(peerfd,NULL,fds[1],NULL,lastonceSize,SPLICE_F_MORE);
            ret=splice(fds[0],NULL,fd,NULL,ret,SPLICE_F_MORE);
        }else {
            ret=splice(peerfd,NULL,fds[1],NULL,1024,SPLICE_F_MORE);
            ret=splice(fds[0],NULL,fd,NULL,ret,SPLICE_F_MORE);
        }
        if (ret<=0) return ret;
        recvSize += ret;
        if(recvSize - lastSize > percentOne) {
            printf("%s has download %5.2f%%\r",pthname, (double)recvSize / filelength * 100);
            fflush(stdout);
            lastSize = recvSize;
        }
        printf("%s has complete 100.00%%\n",pthname);
    }
}
